package cate.game.role.status;

import cate.common.game.GameCollection;
import cate.common.table.d.GDHistory;
import cate.common.table.d.GDHoardTask;
import cp.solution.util.time.TimeSpanCheck;
import cate.common.util.TimeTool;
import cate.game.role.Role;
import cate.game.role.RolePart;
import cate.game.role.status.msg.StatusResp;
import cp.solution.util.time.TimeSpanType;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Calendar;

@Document(GameCollection.NAME_ROLE_STATUS)
@NoteClass(value = "主角的状态")
public class RoleStatus extends RolePart {

    @NoteField(value = "上次数据库保存时间")
    public long lastSaveTime;

    @NoteField(value = "上次退出登录时间")
    public long lastLogoutTime;

    @NoteField(value = "距离上次升级到现在的在线时长")
    public long levelUpTime;

    @NoteField(value = "距离当前主线任务完成玩家已经在线时长")
    public long curMainTaskElapsedTime;

    @NoteField(value = "本次登录时间")
    public long loginTime;

    @NoteField(value = "上一次累计的当日游戏时长")
    public long onlineTimeTodayLast;

    @NoteField(value = "是否在线")
    private boolean online = false;

    @NoteField(value = "最近活跃时间")
    public long activeTime;

    @NoteField(value = "创建时间")
    public long createTime;

    @NoteField(value = "累计登录天数")
    public int loginDays;

    @NoteField(value = "累计游戏时长", detail = "登录时的数值，每次下线时更新")
    public long playTime;

    @NoteField(value = "上次跨天重置时间")
    public long resetTimeDay;

    @NoteField(value = "上次跨周重置时间")
    public long resetTimeWeek;

    @NoteField(value = "上次跨月重置时间")
    public long resetTimeMonth;

    public RoleStatus() {
    }

    public RoleStatus(Role role) {
        super(role);
    }

    @Override
    public void onEnter(){
        //防止每次登录都保存一次
        lastSaveTime = System.currentTimeMillis();
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (createTime == 0) {
            createTime = System.currentTimeMillis();
        }
        if (resetTimeDay == 0) {
            resetTimeDay = System.currentTimeMillis();
        }
        if (resetTimeWeek == 0) {
            resetTimeWeek = System.currentTimeMillis();
        }
        if (resetTimeMonth == 0) {
            resetTimeMonth = System.currentTimeMillis();
        }
    }

    public boolean isOnline() {
        return online;
    }

    private void setOnline(boolean online) {
        // 主角上线时
        if (!this.online && online) {
            this.loginTime = System.currentTimeMillis();
            if (TimeSpanCheck.spanDay(this.loginTime)) {
                this.onlineTimeTodayLast = calcOnlineTimeAfterCurLogin();
            }
        }
        // 主角下线时
        if (this.online && !online) {
            long onlineTimeAfterCurLogin = calcOnlineTimeAfterCurLogin();
            this.onlineTimeTodayLast += onlineTimeAfterCurLogin;
            this.playTime += onlineTimeAfterCurLogin;
            // 下线记录玩家最近一次登出(退出)游戏的时间
            this.lastLogoutTime = System.currentTimeMillis();
            // 下线记录玩家到下一次升级已经花费的在线游戏时长
            this.levelUpTime += (loginTime - System.currentTimeMillis());
            this.curMainTaskElapsedTime += (loginTime - System.currentTimeMillis());
        }
        this.online = online;
    }

    /**
     * 获取本次登录之后的在线时长
     */
    public long calcOnlineTimeAfterCurLogin() {
        if (this.loginTime <= 0) {
            return 0;
        }
        // 具体的逻辑
        final long msDay = 24 * 3600 * 1000L;
        long now = System.currentTimeMillis();
        if (TimeSpanCheck.spanDay(this.loginTime)) {
            int offset = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
            long zeroTime = loginTime - loginTime % msDay + msDay - offset;
            long past = now - zeroTime;
            return past % msDay;
        } else {
            return now - this.loginTime;
        }
    }

    /**
     * 获取今日的在线时长
     */
    public long getOnlineTimeToday() {
        return this.onlineTimeTodayLast + calcOnlineTimeAfterCurLogin();
    }

    /**
     * 获取累计游戏时长
     */
    public long getPlayTime() {
        return playTime;
    }

    /**
     * 活跃
     */
    public void active() {
        this.setOnline(true);
        if (TimeSpanCheck.spanDay(activeTime)) {
            loginDays++;
            noticeUpdate();
            role.getHistory().action.loginDays();
            if (TimeTool.getDistanceDays(createTime, System.currentTimeMillis()) > GDHistory.BACK_LOGIN_CHECK_DAY
                    && TimeTool.getDistanceDays(activeTime, System.currentTimeMillis()) >= GDHistory.BACK_LOGIN_CHECK_DAY) {
                role.getHistory().action.backLogin();
            }
            role.getRes().hoard.addition.addTask(GDHoardTask.LOGIN_ALL);
        }
        this.activeTime = System.currentTimeMillis();
    }

    @Override
    protected void offline() {
        setOnline(false);
    }

    public void noticeUpdate() {
        role.sendNow(new StatusResp(role));
    }

    public RoleStatus copy() {
        RoleStatus cp = new RoleStatus();
        cp.lastSaveTime = this.lastSaveTime;
        cp.loginTime = this.loginTime;
        cp.onlineTimeTodayLast = this.onlineTimeTodayLast;
        cp.online = this.online;
        cp.activeTime = this.activeTime;
        cp.createTime = this.createTime;
        cp.loginDays = this.loginDays;
        cp.playTime = this.playTime;
        return cp;
    }

    /**
     * 处理跨天跨周跨月事件
     *
     * @param force 是否强制执行（在线跨越或者用gm工具调试的时候强制执行一下）
     */
    public TimeSpanType checkTimeSpan(TimeSpanType type, boolean force) {
        // 如果只处理具体的跨时间事件的话，写在下面的分支下
        if (type == TimeSpanType.DAY_SPAN) {
            return (TimeSpanCheck.span(resetTimeDay, type) || force) ? type : null;
        } else if (type == TimeSpanType.WEEK_SPAN) {
            return (TimeSpanCheck.span(resetTimeWeek, type) || force) ? type : null;
        } else if (type == TimeSpanType.MONTH_SPAN) {
            return (TimeSpanCheck.span(resetTimeMonth, type) || force) ? type : null;
        }
        return null;
    }

    public void checkTimeSpans() {
        TimeSpanType dayType = checkTimeSpan(TimeSpanType.DAY_SPAN, false);
        if (dayType != null) {
            role.onDaySpan(true);
        }
        TimeSpanType weekType = checkTimeSpan(TimeSpanType.WEEK_SPAN, false);
        if (weekType != null) {
            role.onWeekSpan(true);
        }
        TimeSpanType monthType = checkTimeSpan(TimeSpanType.MONTH_SPAN, false);
        if (monthType != null) {
            role.onMonthSpan(true);
        }
    }

    @Override
    public void onDaySpan(boolean silence) {
        this.resetTimeDay = System.currentTimeMillis();
    }

    @Override
    public void onWeekSpan(boolean silence) {
        this.resetTimeWeek = System.currentTimeMillis();
    }

    @Override
    public void onMonthSpan(boolean silence) {
        this.resetTimeMonth = System.currentTimeMillis();
    }

    public int getRegisterDay() {
        return TimeTool.getDistanceDays(role.getStatus().createTime, System.currentTimeMillis()) + 1;
    }
}
